﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using DrawZoneCom;
using YRevitJig;

namespace HYElectricSystemDiagram
{
	public class CurveloopsSelector
	{
		public static CurveLoop GetViewCurveLoop(ViewPlan viewPlan)
		{
			CurveLoop curveLoop = new CurveLoop();
			Transaction transaction = new Transaction(viewPlan.Document);
			transaction.Start("CropBox");
			try
			{
				bool cropBoxActive = viewPlan.CropBoxActive;
				viewPlan.CropBoxActive = !cropBoxActive;
				Level genLevel = viewPlan.GenLevel;
				if (genLevel == null)
				{
					return curveLoop;
				}
				double projectElevation = genLevel.ProjectElevation;
				BoundingBoxXYZ cropBox = viewPlan.CropBox;
				XYZ min = cropBox.Min;
				XYZ max = cropBox.Max;
				XYZ xyz = new XYZ(min.X, min.Y, projectElevation);
				XYZ xyz2 = new XYZ(min.X, max.Y, projectElevation);
				XYZ xyz3 = new XYZ(max.X, max.Y, projectElevation);
				XYZ xyz4 = new XYZ(max.X, min.Y, projectElevation);
				curveLoop.Append(Line.CreateBound(xyz, xyz2));
				curveLoop.Append(Line.CreateBound(xyz2, xyz3));
				curveLoop.Append(Line.CreateBound(xyz3, xyz4));
				curveLoop.Append(Line.CreateBound(xyz4, xyz));
				viewPlan.CropBoxActive = cropBoxActive;
				transaction.RollBack();
			}
			catch
			{
				transaction.RollBack();
			}
			return curveLoop;
		}

		public static List<CurveLoop> GetUserSelectedLoopsSystem(ExternalCommandData commandData, Autodesk.Revit.DB.Document docAr, string strSelectItem, out int selectIndex)
		{
			List<CurveLoop> list = new List<CurveLoop>();
			selectIndex = 0;
			FormSelectTypeSystem formSelectTypeSystem = new FormSelectTypeSystem(strSelectItem, commandData);
			if (DialogResult.OK == formSelectTypeSystem.ShowDialog())
			{
				int selectType = formSelectTypeSystem.GetSelectType();
				selectIndex = selectType;
				switch (selectType)
				{
				case 0:
					foreach (List<CurveLoop> list2 in CurveloopsSelector.DrawZoneManual(commandData.Application))
					{
						if (list2.Count > 0)
						{
							list.Add(list2.First<CurveLoop>());
						}
					}
					break;
				case 1:
				{
					ViewPlan viewPlan = commandData.Application.ActiveUIDocument.ActiveView as ViewPlan;
					if (viewPlan != null)
					{
						CurveLoop viewCurveLoop = CurveloopsSelector.GetViewCurveLoop(viewPlan);
						if (viewCurveLoop != null)
						{
							list.Add(viewCurveLoop);
						}
					}
					break;
				}
				case 2:
					return null;
				}
			}
			if (formSelectTypeSystem.DialogResult == DialogResult.Cancel)
			{
				list = null;
				selectIndex = -10;
			}
			return list;
		}

		private static DetailCurve CreateDetailCurve(Autodesk.Revit.DB.Document doc, Curve curve)
		{
			System.Drawing.Color.FromArgb(255, 0, 255);
			Transaction transaction = new Transaction(doc, "DrawCurve");
			transaction.Start();
			DetailCurve result = doc.Create.NewDetailCurve(doc.ActiveView, curve);
			transaction.Commit();
			return result;
		}

		private static List<List<CurveLoop>> DrawZoneManual(UIApplication app)
		{
			UIDocument activeUIDocument = app.ActiveUIDocument;
			Document document = activeUIDocument.Document;
			List<List<CurveLoop>> list = new List<List<CurveLoop>>();
			List<ElementId> list2 = new List<ElementId>();
			TransactionGroup transactionGroup = new TransactionGroup(document, "TransactionGroup");
			transactionGroup.Start();
			XYZ zero = XYZ.Zero;
			try
			{
				XRectJigPtP xrectJigPtP = new XRectJigPtP(activeUIDocument);
				xrectJigPtP.StartPoint = null;
				XYZ ptStart = xrectJigPtP.PickStartPointN("请确定矩形第一个角点：");
				xrectJigPtP.EndPoint = null;
				xrectJigPtP.PickEndPoint(ptStart, "请确定矩形另一对角点：");
				foreach (Curve curve in xrectJigPtP.CreateCurves())
				{
					DetailCurve detailCurve = CurveloopsSelector.CreateDetailCurve(document, curve);
					list2.Add(detailCurve.Id);
				}
				xrectJigPtP.Dispose();
				List<Curve> list3 = new List<Curve>();
				foreach (ElementId elementId in list2)
				{
					DetailCurve detailCurve2 = document.GetElement(elementId) as DetailCurve;
					list3.Add(detailCurve2.GeometryCurve);
				}
				Transaction transaction = new Transaction(document, "CreateFilledRegion");
				transaction.Start();
				document.Delete(list2);
				transaction.Commit();
				List<RichPoint> list4 = CurveloopsSelector.ConstructRichPointSet(list3);
				list4.Sort(new RichPointComparer());
				foreach (ClosedArea closedArea in CurveloopsSelector.GetClosedAreas(list4))
				{
					list.Add(closedArea.getCurveLoopList());
				}
				transactionGroup.Commit();
				transactionGroup.Start();
			}
			catch
			{
			}
			transactionGroup.RollBack();
			return list;
		}

		public static List<RichPoint> ConstructRichPointSet(List<Curve> splitCurves)
		{
			List<RichPoint> list = new List<RichPoint>();
			foreach (Curve curve in splitCurves)
			{
				XYZ ptStart = curve.GetEndPoint(0);
				int num = list.FindIndex((RichPoint a) => a.m_point.IsAlmostEqualTo(ptStart));
				if (-1 == num)
				{
					list.Add(new RichPoint(ptStart, curve));
				}
				else
				{
					list[num].AddCurve(curve);
				}
				XYZ ptEnd = curve.GetEndPoint(1);
				num = list.FindIndex((RichPoint a) => a.m_point.IsAlmostEqualTo(ptEnd));
				if (-1 == num)
				{
					list.Add(new RichPoint(ptEnd, CurveloopsSelector.CreateReversedCurve(curve)));
				}
				else
				{
					list[num].AddCurve(CurveloopsSelector.CreateReversedCurve(curve));
				}
			}
			return list;
		}

		public static List<ClosedArea> GetClosedAreas(List<RichPoint> richPoints)
		{
			List<ClosedArea> list = new List<ClosedArea>();
			while (richPoints.Count > 1)
			{
				List<Curve> list2 = CurveloopsSelector.SearchLongestPath(richPoints);
				int num = -1;
				if (list.Count > 0)
				{
					ClosedArea closedArea = list[list.Count - 1];
					List<XYZ> list3 = new List<XYZ>();
					foreach (Curve curve in closedArea.m_outerBoundary)
					{
						list3.AddRange(curve.Tessellate());
					}
					list2[0].GetEndPoint(0);
				}
				if (1 == num)
				{
					list[list.Count - 1].m_innerBoundary.Add(list2);
				}
				else if (-1 == num)
				{
					ClosedArea closedArea2 = new ClosedArea();
					closedArea2.m_outerBoundary = new List<Curve>();
					closedArea2.m_outerBoundary.AddRange(list2);
					closedArea2.m_innerBoundary = new List<List<Curve>>();
					list.Add(closedArea2);
				}
				foreach (Curve curve2 in list2)
				{
					XYZ ptStart = curve2.GetEndPoint(0);
					int num2 = richPoints.FindIndex((RichPoint a) => a.m_point.IsAlmostEqualTo(ptStart));
					if (-1 != num2)
					{
						foreach (Curve curve3 in richPoints[num2].m_curves)
						{
							XYZ ptEnd = curve3.GetEndPoint(1);
							RichPoint richPoint = richPoints.Find((RichPoint a) => a.m_point.IsAlmostEqualTo(ptEnd));
							for (int i = 0; i < richPoint.m_curves.Count; i++)
							{
								if (richPoint.m_curves[i].GetEndPoint(1).IsAlmostEqualTo(ptStart))
								{
									richPoint.m_curves.RemoveAt(i);
									break;
								}
							}
						}
						richPoints.RemoveAt(num2);
					}
				}
				CurveloopsSelector.DeleteSingleEdgePoint(ref richPoints);
			}
			return list;
		}

		private static List<Curve> SearchLongestPath(List<RichPoint> richPoints)
		{
			XYZ xyz = XYZ.BasisY.Negate();
			double num = 0.0;
			List<Curve> list = new List<Curve>();
			Curve curve = null;
			XYZ ptCurrent = richPoints[0].m_point;
            Predicate<RichPoint> ss9__0 = null;
			do
			{
				Predicate<RichPoint> match;
				if ((match = ss9__0) == null)
				{
					match = (ss9__0 = ((RichPoint a) => a.m_point.IsAlmostEqualTo(ptCurrent)));
				}
				foreach (Curve curve2 in richPoints.Find(match).m_curves)
				{
					XYZ tangentAt = CurveloopsSelector.GetTangentAt(curve2);
					double num2 = xyz.AngleOnPlaneTo(tangentAt, XYZ.BasisZ);
					if (Math.Round(Math.PI*2, 4) == Math.Round(num2, 4))
					{
						num2 = 0.0;
					}
					if (num2 > num)
					{
						curve = curve2;
						num = num2;
					}
				}
				list.Add(curve);
				ptCurrent = curve.GetEndPoint(1);
				xyz = CurveloopsSelector.GetTangentAt(CurveloopsSelector.CreateReversedCurve(curve));
				num = 0.0;
			}
			while (!ptCurrent.IsAlmostEqualTo(richPoints[0].m_point));
			return list;
		}

		private static void DeleteSingleEdgePoint(ref List<RichPoint> richPoints)
		{
			for (int i = 0; i < richPoints.Count; i++)
			{
				RichPoint richPoint = richPoints[i];
				if (1 == richPoint.m_curves.Count)
				{
					XYZ endPoint = richPoint.m_curves[0].GetEndPoint(0);
					XYZ ptEnd = richPoint.m_curves[0].GetEndPoint(1);
					richPoints.RemoveAt(i);
					i--;
					RichPoint richPoint2 = richPoints.Find((RichPoint a) => a.m_point.IsAlmostEqualTo(ptEnd));
					for (int j = 0; j < richPoint2.m_curves.Count; j++)
					{
						if (richPoint2.m_curves[j].GetEndPoint(1).IsAlmostEqualTo(endPoint))
						{
							richPoint2.m_curves.RemoveAt(j);
							if (richPoint2.m_curves.Count == 0)
							{
								richPoints.Remove(richPoint2);
							}
							i = -1;
							break;
						}
					}
				}
			}
			richPoints.TrimExcess();
		}

		private static Curve CreateReversedCurve(Curve orig)
		{
			if (orig is Line)
			{
				return Line.CreateBound(orig.GetEndPoint(1), orig.GetEndPoint(0));
			}
			if (orig is Arc)
			{
				return Arc.Create(orig.GetEndPoint(1), orig.GetEndPoint(0), orig.Evaluate(0.5, true));
			}
			throw new Exception("无法创建方向相反的曲线。");
		}

		private static XYZ GetTangentAt(Curve curve)
		{
			return curve.ComputeDerivatives(0.0, true).BasisX.Normalize();
		}
	}
}
